import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.pircbotx.Channel;
import org.pircbotx.PircBotX;
import org.pircbotx.User;
import pl.shockah.HTTPQuery;
import pl.shockah.StringTools;
import pl.shockah.shocky.Data;
import pl.shockah.shocky.Module;
import pl.shockah.shocky.Utils;
import pl.shockah.shocky.cmds.Command;
import pl.shockah.shocky.cmds.CommandCallback;
import pl.shockah.shocky.cmds.Parameters;
import pl.shockah.shocky.interfaces.IAcceptURLs;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.StringUtils;
public class ModuleTwitter extends Module implements IAcceptURLs {
private final static SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy",Locale.US);
protected Command cmd;
static {
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
}
private final Pattern statusUrl = Pattern.compile("/status(es)?/([0-9]+)");
public String name() {return "twitter";}
public boolean isListener() {return false;}
public void onEnable(File dir) {
Data.config.setNotExists("twitter-dateformat","dd.MM.yyyy HH:mm:ss");
Data.config.setNotExists("twitter-consumerkey","");
Data.config.setNotExists("twitter-consumersecret","");
Data.protectedKeys.add("twitter-consumerkey");
Data.protectedKeys.add("twitter-consumersecret");
Data.protectedKeys.add("twitter-accesstoken");
Command.addCommands(this, cmd = new CmdTwitter());
}
public void onDisable() {
Command.removeCommands(cmd);
}
public String getAccessToken(boolean useCache) {
if (useCache && Data.config.exists("twitter-accesstoken"))
return Data.config.getString("twitter-accesstoken");
String key = Data.config.getString("twitter-consumerkey");
String secret = Data.config.getString("twitter-consumersecret");
if (key.isEmpty() || secret.isEmpty())
return null;
HTTPQuery q;
try {
q = HTTPQuery.create("https://api.twitter.com/oauth2/token",HTTPQuery.Method.POST);
} catch (MalformedURLException e1) {return null;}
try {
String credentials = String.format("%s:%s", URLEncoder.encode(key, "UTF-8"),URLEncoder.encode(secret, "UTF-8"));
q.connect(true,true);
q.setHeaderProperty("Authorization", "Basic "+Base64.encodeBase64String(StringUtils.getBytesUtf8(credentials)));
q.setHeaderProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
q.write("grant_type=client_credentials");
JSONObject json = new JSONObject(q.readWhole());
if (!json.getString("token_type").contentEquals("bearer"))
return null;
String token = json.getString("access_token");
Data.config.set("twitter-accesstoken", token);
return token;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
q.close();
}
return null;
}
public Object getJSON(String url) {
HTTPQuery q = null;
String token = getAccessToken(true);
if (token == null)
return null;
try {
q = HTTPQuery.create(url);
q.connect(true,false);
q.setHeaderProperty("Authorization", "Bearer "+token);
String s = q.readWhole();
if (s.isEmpty())
return null;
if (s.charAt(0)=='[')
return new JSONArray(s);
JSONObject json = new JSONObject(s);
if (json.has("errors")) {
JSONArray errors = json.getJSONArray("errors");
Data.config.remove("twitter-accesstoken");
System.out.print("Twitter errors for ");
System.out.println(url);
for (int i = 0; i < errors.length(); ++i) {
JSONObject error = errors.getJSONObject(i);
System.out.format("Code: %d Message: %s",error.getInt("code"),error.getString("message")).println();
}
return null;
}
return json;
} catch (Exception e) {
e.printStackTrace();
Data.config.remove("twitter-accesstoken");
} finally {
q.close();
}
return null;
}
@Override
public boolean shouldAcceptURL(URL u) {
if (u == null)
return false;
if (!u.getProtocol().startsWith("http"))
return false;
return u.getHost().endsWith("twitter.com");
}
@Override
public void handleURL(PircBotX bot, Channel channel, User sender, List<URL> urls) {
if (bot == null || urls == null || urls.isEmpty() || (channel == null && sender == null))
return;
if (channel != null && !isEnabled(channel.getName()))
return;
StringBuilder sb = new StringBuilder();
Iterator<URL> iter = urls.iterator();
while (iter.hasNext()) {
URL u = iter.next();
Matcher m = statusUrl.matcher(u.getPath());
if (!m.find())
continue;
JSONObject json = (JSONObject)getJSON("https://api.twitter.com/1.1/statuses/show.json?"+HTTPQuery.parseArgs("trim_user","false","id",m.group(2)));
if (json == null)
continue;
try {
JSONObject user = json.getJSONObject("user");
String author = String.format("%s (@%s)",user.getString("name"),user.getString("screen_name"));
String tweet = StringTools.unescapeHTML(json.getString("text"));
Date date = sdf.parse(json.getString("created_at"));
sb.append(author).append(", ").append(Utils.timeAgo(date)).append(": ").append(tweet);
if (iter.hasNext())
sb.append('\n');
} catch (Exception e) {
e.printStackTrace();
}
}
if (sb.length() == 0)
return;
String result = StringTools.formatLines(sb);
if (channel != null)
bot.sendMessage(channel, Utils.mungeAllNicks(channel,0,sender.getNick()+": "+result,sender));
else if (sender != null)
bot.sendMessage(sender, result);
}
public class CmdTwitter extends Command {
public String command() {return "twitter";}
public String help(Parameters params) {
return "twitter\ntwitter {nick} [index] - returns a tweet";
}
public void doCommand(Parameters params, CommandCallback callback) {
if (params.tokenCount < 1 || params.tokenCount > 2) {
callback.type = EType.Notice;
callback.append(help(params));
return;
}
String nick = params.nextParam();
int index = 1;
if (params.tokenCount == 2) {
String indexString = params.nextParam();
try {
index = Integer.parseInt(indexString);
}
catch (NumberFormatException e) {}
}
if (index < 1 || index > 200) {
callback.type = EType.Notice;
callback.append("index must be 1-200");
return;
}
JSONArray array = (JSONArray)getJSON("https://api.twitter.com/1.1/statuses/user_timeline.json?"+HTTPQuery.parseArgs("trim_user","false","exclude_replies","true","screen_name",nick,"count",Integer.toString(index)));
if (array == null||array.length()==0)
return;
if (index > array.length())
index = array.length();
try {
JSONObject json = array.getJSONObject(index-1);
JSONObject user = json.getJSONObject("user");
String author = String.format("%s (@%s)",user.getString("name"),user.getString("screen_name"));
String tweet = StringTools.unescapeHTML(json.getString("text"));
tweet = Utils.mungeAllNicks(params.channel,0,tweet,params.sender);
Date date = sdf.parse(json.getString("created_at"));
callback.append(author).append(", ").append(Utils.timeAgo(date)).append(": ");
callback.append(StringTools.formatLines(tweet));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}